import { _decorator, Component, EventTarget, Game, Input } from "cc";

import {
  MainContainer,
} from "./container";
import { ServiceLocator } from "./service";

import { request, Logger } from "db://assets/util";
import { Chapter } from 'db://assets/store';
import { EventType, FrameType, STATE, TIMER } from "db://assets/enum";
import { DialogContainer } from "./container/DialogContainer";
import { DynamicTasks } from "run-time-opti";
import { AwaitQueue } from "awaitqueue/lib/AwaitQueue";
import { throttle } from "radash";
import { SpineContainer } from "./container/SpineContainer";

const {
  ccclass,
  property,
  menu,
} = _decorator;

@ccclass('MainScreen')
@menu('Screen/MainScreen')
export class MainScreen extends Component {
  #logger = new Logger('主屏幕::MainScreen')

  @property({
    tooltip: '主线视觉容器',
    displayName: '视觉容器',
    type: MainContainer,
  })
  mainContainer: MainContainer

  @property({
    tooltip: '对话框容器',
    displayName: '对话框容器',
    type: DialogContainer,
  })
  dialogContainer: DialogContainer

  @property({
    tooltip: 'Spine容器',
    displayName: 'Spine容器',
    type: SpineContainer,
  })
  SpineContainer: SpineContainer

  #services = ServiceLocator;

  chapter: Chapter;

  #processing = false;

  #events = new EventTarget()

  #tasks = new DynamicTasks()

  frameHandle = {
    [FrameType.BGP]: this.handleBGPFrame.bind(this),
    [FrameType.TEXT]: this.handleTextFrame.bind(this),
    [FrameType.FGP]: this.handleFGPFrame.bind(this),
    [FrameType.INTERACTIVE]: this.handleInteractiveFrame.bind(this),
    [FrameType.BGM]: this.handleBGMFrame.bind(this),
    [FrameType.SPINE]: this.handleSpineFrame.bind(this),
    [FrameType.AUDIO]: this.handleAudio.bind(this),
    [FrameType.TRANSFORM]: this.handleTransformFrame.bind(this),
    [FrameType.BULLET_CHAT]: this.handleBulletChatFrame.bind(this),
  }

  protected onLoad(): void {
    this.#logger.debug('#onLoad')
    this.#services.register(STATE.EVENT, this.#events)
    this.#services.register(STATE.TASK, this.#tasks)
  }

  protected start(): void {
    this.#logger.debug('#start')

    this.node.on(Input.EventType.TOUCH_START, this.#event.onTouch)
    this.#events.on(EventType.FRAME_END, this.#event.frameEnd)
    this.#events.on(EventType.NEXT_FRAME, this.#event.nextFrame)
    this.onInit()
  }

  protected onDestroy(): void {
    this.#events.off(EventType.NEXT_FRAME)
    this.#events.off(EventType.FRAME_END)
  }

  async onInit() {
    this.#logger.debug("#onInit")
    const { status, data } = await request.post<LDAPI.Response<LDChapter.ChapterResponse>>(`api/v1/book/preview`).json()
    if (status === 200) {
      this.#logger.debug('初始化章节 %o', data)
      this.chapter = new Chapter(data.dataJson)
      this.chapter.currentFrameId = this.chapter.state.frames.structure[0].id
      this.#services.register(STATE.CHAPTER, this.chapter)
      this.next()
    }
  }

  #event = {
    onTouch: throttle({ interval: TIMER.THROTTLE }, () => {
      this.#logger.debug('#event.onTouch', this.#processing)
      if (this.#processing) return
      this.chapter.next()
      this.next()
    }),
    frameEnd: () => {
      this.#logger.debug("#event.frameEnd")
      this.#processing = false
    },
    nextFrame: (frameId?: number) => {
      this.#logger.debug("#event.nextFrame", frameId)
      this.chapter.next(frameId)
      this.next()
    },
  }

  next() {
    this.#logger.debug("@next %o", this.chapter.currentFrame.content, this.#processing)
    if ('type' in this.chapter.currentFrame.content && this.chapter.currentFrame.content.type in this.frameHandle) {
      this.#processing = true
      this.frameHandle[this.chapter.currentFrame.content.type](this.chapter.currentFrame)
    } else {
      this.#logger.debug('未处理的帧类型 %o', this.chapter.currentFrame?.content)
    }
  }

  async handleBGPFrame(frame: LDChapter.Frame) {
    this.#logger.debug('处理背景图帧 %o', frame)
    await this.dialogContainer.clear()
    await this.mainContainer.showBGPFrame(frame.content as LDContent.BGPContent)
  }

  async handleFGPFrame(frame: LDChapter.Frame) {
    this.#logger.debug('处理前景图帧 %o', frame)
    await this.dialogContainer.clear()
    await this.mainContainer.showFGPFrame(frame.content as LDContent.FGPContent)
  }

  handleTextFrame(frame: LDChapter.Frame) {
    this.#logger.debug('处理文本帧 %o', frame)
    this.mainContainer.showFGPFrame((frame.content as LDContent.DialogContent).dialog.who)
    this.dialogContainer.showDialog(frame.content as LDContent.DialogContent)
  }

  async handleInteractiveFrame(frame: LDChapter.Frame) {
    const children = frame.children.map(child => this.chapter.getFrame(child) as LDChapter.ChildFrame)
    this.#logger.debug('处理交互帧 %o', frame.content, children)
    await this.dialogContainer.clear()
    this.mainContainer.showInteractiveFrame(frame.content as LDContent.InteractiveContent, children)
  }

  handleBGMFrame(frame: LDChapter.Frame) {
    this.#logger.debug('处理背景音乐帧 %o', frame.content)
    if ('resourceId' in frame.content) this.mainContainer.playBGM(frame.content as LDContent.BGMContent)
    this.#event.nextFrame()
  }

  handleAudio(frame: LDChapter.Frame) {
    this.#logger.debug('处理音效帧 %o', frame.content)
    this.mainContainer.playAudio(frame.content as LDContent.AudioContent)
    this.#event.nextFrame()
  }

  handleSpineFrame(frame: LDChapter.Frame) {
    this.#logger.debug('处理Spine帧 %o', frame.content)
    this.SpineContainer.content = frame.content as LDContent.SpineContent
  }

  async handleTransformFrame(frame: LDChapter.Frame) {
    this.#logger.debug('处理Transform帧 %o', frame.content)
    await this.mainContainer.transformFrame(frame.content as LDContent.TransformContent)
    this.#event.frameEnd()
  }

  handleBulletChatFrame(frame: LDChapter.Frame) {
    this.#logger.debug('处理BulletChat帧 %o', frame.content)
    this.mainContainer.showBulletChat(frame.content as LDContent.BulletChatContent)
    this.#event.nextFrame()
  }
}
